/***********************************
 * 同花顺-量化助手
 * @author 魔女小溪
 * @date 2025-09-23 12:50
 ***********************************/
app.cache = createCache()
app.auto = {
    website : 'https://gitee.com/monvxiaoxi/autojs',
    headers: {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
        'Host': 'gitee.com',
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
    },
    menu: {},
    menuExclude: ['hello.js'],
    cfg: {
        /*窗口坐标*/
        btnTitle: '请选择执行脚本', windowX: 200, windowY: 0, rawY: 0, downTime: 0,
        /*执行状态：0停止、1启动*/
        state: 0,
        version: 'V1.0.0',
        history: [
            '1.【新增】删除条件单',
            '2.【新增】在线更新脚本',
            '3.【新增】程序退出',
        ],
        downURL: 'https://gitee.com/monvxiaoxi/autojs/raw/master/ui/同花顺量化助手.js'
    }
}

/*入口程序*/
!function main(){
    getScriptList(function(menu){
        app.auto.menu = menu
        app.auto.cfg.windowY = app.cache.get('windowY') || 0
        // 启动同花顺
        launchApp("同花顺") && sleep(1000)
        initWindow()
    })
}()

/*获取脚本列表*/
function getScriptList(fn){
    const {website, headers, menuExclude} = app.auto
    const html = http.get(website, {headers}).body.string()
    const regex = /<a class="tree-folder-item"\s+.*href="(.*?)"[^>]*>(.*?)<\/a>/g
    let match, menu = {};
    while ((match = regex.exec(html)) !== null) {
        if (match[1] && match[1].endsWith('.js') && !menuExclude.includes(match[2])) {
            menu[match[2].replace('.js', '')] = match[1].replace('blob', 'raw')
        }
    }
    if (Object.keys(menu).length>0) {
        fn && fn(menu)
    }else{alert('获取远程脚本仓库为空！')}
    return menu
}

/*获取脚本内容*/
function getScriptContent(url){
    const {website, headers} = app.auto
    const baseUrl = website.substring(0, 17)
    const html = http.get(baseUrl+url, {headers}).body.string()
    return html
}

/*执行脚本*/
function reqExecScript(name, url){
    const content =  getScriptContent(url)
    const scriptContent = "app.cache = createCache()"+createCache.toString()+doClick.toString()+content+"\nfunction dostop(text){events.broadcast.emit('dostop', text)}\nsetInterval(()=>{}, 1000)"
    name = name.replace(/\(.*?\)|（.*?）/, '')
    ui.run(function(){window.ok.setText(`${name}，勿动屏幕...`)})
    const e = engines.execScript(name, scriptContent)
    sleep(1000) || (app.auto.scriptEngine = e.getEngine())
}

/*初始化操作窗口*/
function initWindow(){
    window = floaty.rawWindow(
        <frame w="{{device.width-(app.auto.cfg.windowX*2)}}px" bg="#009972" h="36">
            <horizontal>
                <button id="ok" text="{{app.auto.cfg.btnTitle}}" w="*" alpha="0.8" color="#ffffff" style="Widget.AppCompat.Button.Borderless"/>
            </horizontal>
        </frame>
    )
    window.setPosition(app.auto.cfg.windowX, app.auto.cfg.windowY)
    window.ok.setOnTouchListener(function (view, event) {
        if (event.getAction() == event.ACTION_DOWN) {
            app.auto.cfg.rawY = event.getRawY()
            app.auto.cfg.windowY = window.getY()
            app.auto.cfg.downTime = new Date().getTime()
        }
        else if (event.getAction() == event.ACTION_MOVE){
            let my = event.getRawY() - app.auto.cfg.rawY
            if (my > 10 || my < 0) {
                let py = app.auto.cfg.windowY + (event.getRawY() - app.auto.cfg.rawY)
                let maxHeight = device.height - device.getVirtualBarHeigh() - 100
                window.setPosition(app.auto.cfg.windowX, py > maxHeight ? maxHeight : py < 0 ? 0 : py)
            }
        }
        else if (event.getAction() == event.ACTION_UP) {
            if (Math.abs(event.getRawY() - app.auto.cfg.rawY) < 10 && (new Date().getTime() - app.auto.cfg.downTime) <= 250) {
                /*点击事件*/
                log(app.auto.cfg.state == 0 ? dostart() : dostop())
            } else if (app.auto.cfg.state == 0 && Math.abs(event.getRawY() - app.auto.cfg.rawY) < 10 && (new Date().getTime() - app.auto.cfg.downTime) > 250) {
                /*长按事件*/
                dialogs.select('功能&设置', ['删除条件单(Delete)', '检查更新(Check)', '退出(Exit)']).then(i => {
                    i+1 == 1 && confirm(`是否确认删除条件单?`).then(val =>{
                        app.autoMata.autoSubmit = val ? !autoSubmit : autoSubmit
                        app.cache.set(app.autoMata)
                    });
                    i == 1 && onlineCheckUpdate()
                    i == 2 && exit()
                })
            } else { 
                app.cache.set('windowY', window.getY()) 
            }
        }
        return true
    })
    /*保持窗口线程一直活跃*/
    setInterval(()=>{}, 1000)
    return true
}

/*启动*/
function dostart(){
    if (app.auto.cfg.state == 0) {
        const {menu} = app.auto
        const menuNames = Object.keys(menu)
        dialogs.select("请选择执行脚本", menuNames).then(i => {
            i >= 0 && threads.start(function(){
                app.auto.cfg.state = 1
                ui.run(function(){window.ok.setText('正在执行，请勿动屏幕...')})
                reqExecScript(menuNames[i], menu[menuNames[i]])
            })
        })
    }
    return 'starting...'
}

/*程序停止*/
function dostop(text){
    if (app.auto.cfg.state == 1) {
        setTimeout(() => {
            try {
                app.auto.scriptEngine && app.auto.scriptEngine.forceStop()
                threads.shutDownAll()
            } catch (err) {log('停止脚本运行异常', err)}
            app.auto.cfg.state = 0
            ui.run(function(){window.ok.setText('请选择执行脚本')})
            text && alert(text)
        }, 1000)

    }  
    return 'stopping...'
}
events.broadcast.on('dostop', dostop)

/*在线更新源码*/
function onlineCheckUpdate(){
    const {version, history, downURL} = app.auto.cfg
    dialogs.build({
        title: `检查更新脚本-${version}`,
        content: history.join('\n'),
        positive: "更新",
        negative: "取消"
    })
    .on("positive", () => {
        app.downloadDialog = dialogs.build({
            title: "下载中...",
            negative: "取消",
            progress: {max: 100, showMinMax: true},
            autoDismiss: false
        }).on("negative", ()=>{app.downloadDialog.dismiss() || (app.downloadDialog = null)}).show()
        app.downloadDialog.setProgress(90)
        threads.start(function(){
            const {statusCode, body} =  http.get(downURL)
            if (statusCode == 200) {
                const fileName = downURL.substring(downURL.lastIndexOf('/')+1)
                const filePath = `${files.cwd()}/${fileName}`
                files.writeBytes(filePath, body.bytes())
                app.downloadDialog.setProgress(100) || sleep(1000)
                app.downloadDialog.dismiss() || (app.downloadDialog = null)
                alert('下载成功，程序将退出。\n请重新启动程序！')
                exit()
            }
        })
    }).show()
}

/*点击事件*/
function doClick(selector, secs, isCache) {
    arguments.length>1 && (typeof(secs) == 'boolean' ? (isCache=secs)+(secs=void 0) : isCache)
    let success = false, cx = 0, cy = 0, key = selector.toString()
    if (isCache) {
        let btn = app.cache.clickXY[key]
        if (btn) {
            cx = btn.cx
            cy = btn.cy
        }
    }
    if (cx==0 && cy==0) {
        selector = typeof(selector) == 'string' ? text(selector) : selector
        let btn = selector.findOne(5000)
        if (btn) {
            cx = Math.abs(btn.bounds().centerX())
            cy = Math.abs(btn.bounds().centerY())
        }
    }
    if (cx>0 && cy>0) {
        success = click(cx, cy)
        if (success) {
            isCache && (app.cache.clickXY[key] = {cx, cy})
            secs && sleep(secs)
        }
    }
    return success
}

/*缓存操作*/
function createCache() {
    return {
        clickXY: {},
        storage: storages.create('ths'),
        get: function (key) {
            const data = this.storage.get(device.brand)
            return data ? data[key] : (void 0)
        },
        set: function (key, value) {
            const data = this.storage.get(device.brand) || {key: value}
            data[key] = value
            return this.storage.put(device.brand, data), true
        },
        clear: function () {
            return this.storage.remove(device.brand), true
        }
    }
}
